package com.example.nccdeploytool.util;

import com.ctc.wstx.util.StringUtil;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.Properties;
import java.util.Vector;

/**
 * SFTP工具类
 */
public class SFTPUtil {

    /**
     * 远程登录
     */
    public static Session sshRemoteCallLogin(String host, int port, String userName, String passWord) {
        Session session = null;
        try {
            // 创建jSch对象
            JSch jSch = new JSch();
            // 获取到jSch的session, 根据用户名、主机ip、端口号获取一个Session对象
            session = jSch.getSession(userName, host, port);
            // 设置密码
            session.setPassword(passWord);

            // 通过Session建立连接
            Properties config = new Properties();
            config.put("PubkeyAcceptedAlgorithms", "ssh-rsa,ssh-dss,sm2,sm2-cert,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");
            config.put("StrictHostKeyChecking", "no");
//            config.put("PreferredAuthentications", "publickey,password");

//            // 简单的 Logger 实现
//            JSch.setLogger(new com.jcraft.jsch.Logger() {
//                public boolean isEnabled(int level) {
//                    return true;
//                }
//                public void log(int level, String message) {
//                    System.out.println("JSch: " + message);
//                }
//            });


            session.setConfig(config); // 为Session对象设置properties
            // session.setTimeout(3000);// 设置超时
            session.connect(); // 通过Session建立连接
            System.out.println("主机登录成功, ip = " + host + ", userName = " + userName);
            return session;
        } catch (JSchException e) {
            System.out.println("主机登录失败, ip = " + host + ", userName = " + userName + ", Exception:" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 关闭远程登录
     */
    public static boolean closeSession(Session session) {
        // 调用session的关闭连接的方法
        if (session != null) {
            // 如果session不为空,调用session的关闭连接的方法
            session.disconnect();
            return true;
        }
        return false;
    }

    /**
     * 关闭远程登录sftp
     */
    public static boolean closeSFTP(ChannelSftp sftp) {
        // 调用session的关闭连接的方法
        if (sftp != null) {
            // 如果session不为空,调用session的关闭连接的方法
            sftp.disconnect();
            return true;
        }
        return false;
    }


    /**
     * 从win上传linux文件
     */
    public static void uploadFile(String sourceFilePath, String sourceFileName, String targetFilePath, String targetFileName, Session session) {
        try {
            // 打开channelSftp
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            // 远程连接
            channelSftp.connect();
            if (!isDirExist(targetFilePath, channelSftp)) {
                String[] pathArry = targetFilePath.split("/");
                StringBuffer filePath = new StringBuffer("/");
                for (String path : pathArry) {
                    if (path.equals("")) {
                        continue;
                    }
                    filePath.append(path).append("/");
                    if (!isDirExist(filePath.toString(), channelSftp)) {
                        // 建立目录
                        channelSftp.mkdir(filePath.toString());
                    }
                }
            }

            // 将文件进行上传(sftp协议)
            // 采用默认的传输模式:OVERWRITE
            channelSftp.put(new FileInputStream(sourceFilePath + "/" + sourceFileName), targetFilePath + "/" + targetFileName, ChannelSftp.OVERWRITE);
            // 切断远程连接
            channelSftp.exit();
            System.out.println("文件[" + targetFileName + "]上传成功");
        } catch (JSchException | SftpException | FileNotFoundException e) {
            closeSession(session);
            System.out.println("文件[" + targetFileName + "]上传异常：" + e.getMessage());
            throw new RuntimeException(e);
        }
    }


    public static void uploadFile(InputStream inputStream, String targetFilePath, String targetFileName, Session session) {
        try {
            // 打开channelSftp
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            // 远程连接
            channelSftp.connect();
            if (!isDirExist(targetFilePath, channelSftp)) {
                String[] pathArry = targetFilePath.split("/");
                StringBuffer filePath = new StringBuffer("/");
                for (String path : pathArry) {
                    if (path.equals("")) {
                        continue;
                    }
                    filePath.append(path).append("/");
                    if (!isDirExist(filePath.toString(), channelSftp)) {
                        // 建立目录
                        channelSftp.mkdir(filePath.toString());
                    }
                }
            }

            // 将文件进行上传(sftp协议)
            // 采用默认的传输模式:OVERWRITE
            channelSftp.put(inputStream, targetFilePath + "/" + targetFileName, ChannelSftp.OVERWRITE);
            // 切断远程连接
            channelSftp.exit();
            System.out.println("文件[" + targetFileName + "]上传成功");
        } catch (JSchException | SftpException e) {
            closeSession(session);
            System.out.println("文件[" + targetFileName + "]上传异常：" + e.getMessage());
            throw new RuntimeException(e);
        }
    }


    /**
     * 判断目录是否存在
     */
    public static boolean isDirExist(String directory, ChannelSftp sftp) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 判断目录是否存在
     */
    public static boolean isExist(String path, ChannelSftp sftp) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS attrs = sftp.lstat(path);
            isDirExistFlag = attrs != null;

        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            } else {
                e.printStackTrace();
            }
        }
        return isDirExistFlag;
    }

    public static void write(String path, byte[] content, ChannelSftp sftp) throws Exception {
        // 将字符串转换为输入流并上传
        try (ByteArrayInputStream inputStream =
                     new ByteArrayInputStream(content)) {
            sftp.put(inputStream, path);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String read(String path, ChannelSftp sftp) throws Exception {
        // 将字符串转换为输入流并上传
        // 读取文件内容
        StringBuilder content = new StringBuilder();
        try (
                InputStream inputStream = sftp.get(path);
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line).append("\n");
            }
        }
        return content.toString();
    }


    public static boolean renameTo(String oldFilePath, String newFilePath, ChannelSftp sftp) throws Exception {
        // 执行重命名
        sftp.rename(oldFilePath, newFilePath);
        return true;
    }


    /**
     * 从linux下载文件到win
     */
    public static void fileDownload(String sourceFilePath, String sourceFileName, String targetFilePath, String targetFileName, Session session) {
        String sourceCompletePath = sourceFilePath + "/" + sourceFileName;
        try {
            // src 是linux服务器文件地址,dst 本地存放地址
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            // 远程连接
            channelSftp.connect();
            File folder = new File(targetFilePath);
            // 目标文件路径不存在时创建文件夹
            if (!folder.exists() && !folder.isDirectory()) {
                folder.mkdirs();
            }
            // 下载文件,多个重载方法
            channelSftp.get(sourceCompletePath, targetFilePath + "/" + targetFileName);
            // 切断远程连接,quit()等同于exit(),都是调用disconnect()
            channelSftp.quit();
            // channelSftp.disconnect();
            System.out.println("文件[" + sourceFileName + "]下载成功");
        } catch (JSchException | SftpException e) {
            closeSession(session);
            System.out.println("文件[" + sourceFileName + "]下载异常：" + (e.getMessage().toLowerCase().equals("no such file") ? (sourceCompletePath + " (系统找不到指定的文件。)") : e.getMessage()));
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除linux端文件
     */
    public static void deleteFile(String sourceFilePath, String sourceFileName, Session session) {
        try {
            // 打开openChannel的sftp
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            // 远程连接
            channelSftp.connect();
            // 删除文件
            channelSftp.rm(sourceFilePath + "/" + sourceFileName);
            // 切断远程连接
            channelSftp.exit();
            System.out.println("文件[" + sourceFileName + "]删除成功");
        } catch (JSchException | SftpException e) {
            closeSession(session);
            System.out.println("文件[" + sourceFileName + "]删除异常：" + e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除linux端文件
     */
    public static void delete(String path, ChannelSftp sftp) throws Exception {
        SftpATTRS attrs = sftp.stat(path);
        if (attrs.isDir()) {
            System.out.println("删除目录");
            sftp.rmdir(path);
        } else {
            System.out.println("删除文件");
            sftp.rm(path);
        }
    }

    /**
     * 列出linux目录下的文件
     */
    public static Vector listFiles(String sourceFilePath, Session session) {
        try {
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            // 远程连接
            channelSftp.connect();
            // 显示目录信息
            Vector vector = channelSftp.ls(sourceFilePath);
            // 切断连接
            channelSftp.exit();
//            System.out.println("目录[" + sourceFilePath + "]下的文件列表" + vector);
            return vector;
        } catch (JSchException | SftpException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 列出linux目录下的文件
     */
    public static Vector listFiles(String sourceFilePath, ChannelSftp channelSftp) {
        try {
            // 显示目录信息
            Vector vector = channelSftp.ls(sourceFilePath);
//            System.out.println("目录[" + sourceFilePath + "]下的文件列表" + vector);
            return vector;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行相关的命令
     */
    public static String execCommand(String command, Session session) {
        String res = "";
        InputStream inputStream = null; // 输入流(读)
        ChannelExec channel = null; // 定义channel变量
        try {
            // 如果命令command不等于null
            if (command != null) {
                // 打开channel
                //说明：exec用于执行命令;sftp用于文件处理
                channel = (ChannelExec) session.openChannel("exec");


                channel.setPty(true);
                channel.setPtySize(550, 60, 0, 0); // 可以动态调整

                // 设置command
                channel.setCommand(command);
                // channel进行连接
                channel.connect();
                // 获取到输入流
                inputStream = channel.getInputStream();
                // 执行相关的命令
                res = processDataStream(inputStream);
                // 打印相关的命令
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (channel != null) {
                channel.disconnect();
            }
        }
        return res;
    }

    /**
     * 执行相关的命令
     */
    public static String execCommandShell(String command, Session session) {
        String res = "";
        ChannelShell channel = null; // 定义channel变量

        AssertUtils.check(StringUtils.isNotEmpty(command), "cmd 不能为空");

        try {
            // 如果命令command不等于null
            // 打开channel
            //说明：exec用于执行命令;sftp用于文件处理
            channel = (ChannelShell) session.openChannel("shell");

            // jsch 自动管理
            InputStream in = channel.getInputStream();
            OutputStream out = channel.getOutputStream();

            // channel进行连接
            channel.connect();

            readShell(channel, in, out, null, 10000);

            res = readShell(channel, in, out, command, 10000);


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (channel != null) {
                channel.disconnect();
            }
        }
        System.out.println("shell end");
        return res;
    }


    public static String readShell(ChannelShell channel, InputStream in, OutputStream out, String cmd, long timeout)
            throws Exception {
        long lastDataTime = System.currentTimeMillis();
        StringBuffer output = new StringBuffer();
        byte[] buffer = new byte[1024];

        if (StringUtils.isNotEmpty(cmd)) {
            out.write((cmd + "\n").getBytes());
            out.flush();
        }

        Thread.sleep(1000); // 等待系统反应

        while (channel.isConnected()) {

            while (in.available() > 0){
                int bytesRead = in.read(buffer, 0, 1024);
                if (bytesRead < 0) {
                    System.out.println("bytesRead = " + bytesRead);
                    break;
                }


                String data = new String(buffer, 0, bytesRead);
                output.append(data);
                lastDataTime = System.currentTimeMillis();

                System.out.print(data); // 实时输出

                // 关键：检测命令提示符，表示命令执行完毕
                if (data.endsWith("$ ") || data.endsWith("# ") || data.endsWith("> ")) {
                    // 命令执行完毕，返回结果
                    return output.toString();
                }
            }

            // 超时保护：如果5秒没有新数据，认为命令已完成
            if (System.currentTimeMillis() - lastDataTime > timeout) {
                System.out.println("超时:" + (System.currentTimeMillis() - lastDataTime));
                break;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        System.out.println("channel.isConnected(), in.available()" +channel.isConnected() + (in.available() > 0));
        return output.toString();

    }


    /**
     * 对将要执行的linux的命令进行遍历
     */
    public static String processDataStream(InputStream inputStream) throws Exception {
        StringBuffer strBuffer = new StringBuffer();
        try (BufferedReader bufReader = new BufferedReader(new InputStreamReader(inputStream))) {
            String result;
            while ((result = bufReader.readLine()) != null) {
                strBuffer.append(result + "\n");
            }
        } catch (Exception e) {
            throw new RuntimeException("获取数据流失败: " + e);
        }
        return strBuffer.toString();
    }


}
